#pragma once

#include <open62541.h>
#include <string>
#include <vector>
#include <map>

#define MAX_STRINGBYTES       1000

typedef enum _ModeulType
{
	PRLINE = 1001,
	CPU,
	STATION,
	ROBOT,
	VISION,
	STRIP,
	MANAGE
}ModeulType;

typedef struct _PRLine
{
	int num;
	char describe[1];
}PRLine;

typedef struct _PCInfo
{
	char CPUInfo[MAX_STRINGBYTES];
	char MemInfo[MAX_STRINGBYTES];
	char DiskInfo[MAX_STRINGBYTES];
}PCInfo;

typedef struct _StationInfo
{
	char factory_info[MAX_STRINGBYTES];
	char device_info[MAX_STRINGBYTES];
	char arm_info[MAX_STRINGBYTES];
	char assemble_info[MAX_STRINGBYTES];
	char plc_info[MAX_STRINGBYTES];
	char vision_module[MAX_STRINGBYTES];
	PCInfo pc_info;
	int valtage;
	float air_pressure;
	char fault_type[2];
}StationInfo;

typedef struct _RobotModule
{
	bool init;
	bool fetch_signal1;
	bool fetch_signal2;
	bool fetch_signal3;
	bool analysis_signal;
	bool label_signal1;
	bool label_signal2;
	bool label_signal3;
}RobotModule;

typedef struct _VisionModule
{
	bool init;
	bool capture_signal;
	bool pos_signal;
}VisionModule;

typedef struct _StripModule
{
	bool init;
	float speed;
	float arrive_delay;
	float alarm_delay;
}StripModule;

typedef struct _Time
{
	int sec;
	int min;
	int hour;
}Time;

typedef struct _ManageModule
{
	Time start_time;
	Time performance_time;
}ManageModule;



class ServerCore
{
public:
	ServerCore();
	~ServerCore();

	int run();
	void server_stop();
	bool if_running();

	int renameNodeId(ModeulType node, std::string new_name);
	int updatePRLine(PRLine new_value);
	int updateStationInfo(StationInfo new_value);
	//int updateStripModule(StripModule new_value);
private:
	UA_Server* server = NULL;
	UA_Boolean running = false;
	UA_ServerConfig* config = NULL;

	//Object Type
	UA_NodeId PRLineTypeId  = { 1, UA_NODEIDTYPE_NUMERIC, {PRLINE} };
	UA_NodeId CPUTypeId     = { 1, UA_NODEIDTYPE_NUMERIC, {CPU} };
	UA_NodeId StationTypeId = { 1, UA_NODEIDTYPE_NUMERIC, {STATION} };
	UA_NodeId RobotTypeId   = { 1, UA_NODEIDTYPE_NUMERIC, {ROBOT} };
	UA_NodeId VisionTypeId  = { 1, UA_NODEIDTYPE_NUMERIC, {VISION} };
	UA_NodeId StripTypeId   = { 1, UA_NODEIDTYPE_NUMERIC, {STRIP} };
	UA_NodeId ManageTypeId  = { 1, UA_NODEIDTYPE_NUMERIC, {MANAGE} };

	//infomation model
	UA_NodeId PRLineNodeId;
	UA_NodeId StationNodeId;
	UA_NodeId RobotNodeId;
	UA_NodeId VisionNodeId;
	UA_NodeId StripNodeId;
	UA_NodeId ManageNodeId;
	std::map<int, std::string>name_dict = {
		{PRLINE, "PRLineNodeId"},
		{STATION, "StationNodeId"},
		{ROBOT, "RobotNodeId"},
		{VISION, "VisionNodeId"},
		{STRIP, "StripNodeId"},
		{MANAGE, "ManageNodeId"}
	};
	std::map<int, UA_NodeId*>node_dict = {
		{PRLINE, &PRLineNodeId},
		{STATION, &StationNodeId},
		{ROBOT, &RobotNodeId},
		{VISION, &VisionNodeId},
		{STRIP, &StripNodeId},
		{MANAGE, &ManageNodeId}
	};
	
	//Data instance
	PRLine prline;
	StationInfo station_info;
	RobotModule robot_module;
	VisionModule vision_module;
	StripModule strip_module;
	ManageModule manage_module;

	void init_variable();
	void constructObjectType(UA_Server* server);

	void addVariableNode();
	static void RobotBeforeRead(UA_Server* server,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* nodeid, void* nodeContext,
		const UA_NumericRange* range, const UA_DataValue* data);
	static void RobotAfterWrite(UA_Server* server,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* nodeid, void* nodeContext,
		const UA_NumericRange* range, const UA_DataValue* data);
	void addRobotNode();
	static void VisionBeforeRead(UA_Server* server,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* nodeid, void* nodeContext,
		const UA_NumericRange* range, const UA_DataValue* data);
	static void VisionAfterWrite(UA_Server* server,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* nodeid, void* nodeContext,
		const UA_NumericRange* range, const UA_DataValue* data);
	void addVisionNode();
};

